#include <ximera/graphics/ogre/entity.hpp>
#include <ximera/graphics/ogre/ogre.hpp>
#include <ximera/common/utils.hpp>

namespace ximera { namespace graphics { namespace ogre
{
    Entity::Entity(Ogre::SceneManager* ogreSceneManager, String const& name, PrefabEntityType type)
        : IEntity(name),
          _ogreSceneManager(ogreSceneManager),
          _ogreEntity(0)
    {
        XIMERA_ASSERT_DEF(ogreSceneManager);

        try
        {
            _ogreEntity = ogreSceneManager->createEntity(string_util::wstr2str(name),
                static_cast<Ogre::SceneManager::PrefabType>(type.value));
        }
        catch (Ogre::Exception& e)
        {
            XIMERA_THROW_OGRE_EXCEPTION(e);
        }
    }

    Entity::Entity(Ogre::SceneManager* ogreSceneManager, String const& name, String const& meshName)
        : IEntity(name),
          _ogreSceneManager(ogreSceneManager),
          _ogreEntity(0)
    {
        XIMERA_ASSERT_DEF(ogreSceneManager);

        try 
        {
            _ogreEntity = ogreSceneManager->createEntity(string_util::wstr2str(name), string_util::wstr2str(meshName));
        }
        catch (Ogre::Exception& e)
        {
            XIMERA_THROW_OGRE_EXCEPTION(e);
        }
    }

    Entity::Entity(Ogre::SceneManager* ogreSceneManager, Ogre::Entity* ogreEntity)
        : _ogreSceneManager(ogreSceneManager),
          _ogreEntity(ogreEntity)
    {
        XIMERA_ASSERT_DEF(ogreSceneManager);
        XIMERA_ASSERT_DEF(ogreEntity);
    }

    Entity::~Entity()
    {
        _ogreSceneManager->destroyEntity(_ogreEntity);
    }    

    void Entity::useCameraRenderMode(bool value)
    {
        _ogreEntity->setPolygonModeOverrideable(value);
    }

    bool Entity::visible() const
    {
        return _ogreEntity->getVisible();
    }

    void Entity::visible(bool vis)
    {
        _ogreEntity->setVisible(vis);
    }

    String Entity::materialName() const
    {
        return L"";
    }

    void Entity::materialName(String const& name)
    {
        _ogreEntity->setMaterialName(string_util::wstr2str(name));
    }

    void Entity::descendantMaterial(String const& name, String const& material)
    {
    }

    bool Entity::castShadows() const
    {
        return _ogreEntity->getCastShadows();
    }

    void Entity::castShadows(bool casts)
    {
        _ogreEntity->setCastShadows(casts);
    }

    void Entity::enableAnimation(String const& name, bool enable)
    {
        Ogre::AnimationState* animState = _ogreEntity->getAnimationState(string_util::wstr2str(name));

        if (animState)
            animState->setEnabled(enable);
    }

    void Entity::step(String const& animName, Real secs)
    {
        Ogre::AnimationState* animState = _ogreEntity->getAnimationState(string_util::wstr2str(animName));

        if (animState)
            animState->addTime(secs);
    }

    void Entity::step(Real secs)
    {
        Ogre::ConstEnabledAnimationStateIterator iter = 
            _ogreEntity->getAllAnimationStates()->getEnabledAnimationStateIterator();

        while (iter.hasMoreElements())
        {
            Ogre::AnimationState* animState = iter.getNext();
            animState->addTime(secs);
        }
    }

    void Entity::attach(String const& boneName, Attachable* object)
    {
        IAttachable* attachable = dynamic_cast<IAttachable*>(object);
        XIMERA_ASSERT(attachable, XIMERA_THROW(InvalidParamException, L"Object must be attachable!"));

        _ogreEntity->attachObjectToBone(string_util::wstr2str(boneName), attachable->ogreMovableObject());
    }
}}}